package cn.ultrarisk.scadmin.manager.biz.common.service;

import cn.ultrarisk.mybatis.extension.query.Query;
import cn.ultrarisk.scadmin.manager.biz.common.context.OperationType;
import cn.ultrarisk.scadmin.manager.biz.common.dao.DictDAO;
import cn.ultrarisk.scadmin.manager.biz.common.dao.OperationLogDAO;
import cn.ultrarisk.scadmin.manager.biz.common.dao.SchedulerJobDAO;
import cn.ultrarisk.scadmin.manager.biz.common.entity.Dict;
import cn.ultrarisk.scadmin.manager.biz.common.entity.OperationLog;
import cn.ultrarisk.scadmin.manager.biz.common.entity.SchedulerJob;
import cn.ultrarisk.scadmin.manager.biz.context.RequestContext;
import cn.ultrarisk.scadmin.manager.biz.solr.dao.SolrCollectionDAO;
import cn.ultrarisk.scadmin.manager.biz.solr.dao.SolrNodeDAO;
import cn.ultrarisk.scadmin.manager.biz.solr.dao.SolrReplicaDAO;
import cn.ultrarisk.scadmin.manager.biz.solr.entity.SolrCollection;
import cn.ultrarisk.scadmin.manager.biz.solr.entity.SolrNode;
import cn.ultrarisk.scadmin.manager.biz.solr.entity.SolrReplica;
import cn.ultrarisk.scadmin.manager.biz.user.dao.AdminDAO;
import cn.ultrarisk.scadmin.manager.biz.user.dao.RoleDAO;
import cn.ultrarisk.scadmin.manager.biz.user.entity.Admin;
import cn.ultrarisk.scadmin.manager.biz.user.entity.Role;
import cn.ultrarisk.scadmin.manager.biz.zookeeper.dao.ZkBackupDAO;
import cn.ultrarisk.scadmin.manager.biz.zookeeper.dao.ZkNodeDAO;
import cn.ultrarisk.scadmin.manager.biz.zookeeper.entity.ZkBackup;
import cn.ultrarisk.scadmin.manager.biz.zookeeper.entity.ZkNode;
import cn.ultrarisk.scadmin.manager.util.CollectionUtil;
import cn.ultrarisk.scadmin.manager.util.DateUtil;
import cn.ultrarisk.scadmin.manager.util.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.net.InetAddress;
import java.util.Date;
import java.util.List;

import static cn.ultrarisk.scadmin.manager.biz.common.context.OperationType.*;

/**
 * 操作日志数据操作类
 *
 * @author sevendlong(lin23871@163.com)
 * @date 2014/3/28
 * @since V1.0
 */
@Service
@Transactional(propagation = Propagation.REQUIRED)
public class OperationLogService {
    @Autowired
    private OperationLogDAO operationLogDAO;
    @Autowired
    private SolrCollectionDAO solrCollectionDAO;
    @Autowired
    private DictDAO dictDAO;
    @Autowired
    private SchedulerJobDAO schedulerJobDAO;
    @Autowired
    private AdminDAO adminDAO;
    @Autowired
    private RoleDAO roleDAO;
    @Autowired
    private ZkBackupDAO zkBackupDAO;
    @Autowired
    private ZkNodeDAO zkNodeDAO;
    @Autowired
    private SolrNodeDAO solrNodeDAO;
    @Autowired
    private SolrReplicaDAO solrReplicaDAO;

    public void createDictLog(OperationType type, Object... querys) {
        Object query = (querys != null && querys.length > 0) ? querys[0] : null;
        String dictName = null;
        if (query != null) {
            if (query.getClass() == Integer.class) {
                dictName = dictDAO.get((Integer) query, Dict.NAME).getName();
            } else if (query.getClass() == Dict.class) {
                dictName = ((Dict) query).getName();
            }
        }
        if (type == DICT_CREATE) {
            createLog(type, DICT_CREATE.remark(dictName));
        } else if (type == DICT_UPDATE) {
            createLog(type, DICT_UPDATE.remark(dictName));
        } else if (type == DICT_DELETE) {
            createLog(type, DICT_DELETE.remark(dictName));
        }
    }

    public void createSchedulerJobLog(OperationType type, Object... querys) {
        Object query = (querys != null && querys.length > 0) ? querys[0] : null;
        String jobName = null;
        if (query != null) {
            if (query.getClass() == Integer.class) {
                jobName = schedulerJobDAO.get((Integer) query, SchedulerJob.NAME).getName();
            } else if (List.class.isAssignableFrom(query.getClass())) {
                jobName = CollectionUtil.join(schedulerJobDAO.findColumn(Query.inQuery(SchedulerJob.ID, query), SchedulerJob.NAME, true, true), ",");
            } else if (query.getClass() == SchedulerJob.class) {
                jobName = ((SchedulerJob) query).getName();
            }
        }
        if (type == SCHEDULER_CREATE) {
            createLog(type, SCHEDULER_CREATE.remark(jobName));
        } else if (type == SCHEDULER_UPDATE) {
            createLog(type, SCHEDULER_UPDATE.remark(jobName));
        } else if (type == SCHEDULER_DELETE) {
            createLog(type, SCHEDULER_DELETE.remark(jobName));
        } else if (type == SCHEDULER_ENABLE) {
            createLog(type, SCHEDULER_ENABLE.remark(jobName));
        } else if (type == SCHEDULER_DISABLE) {
            createLog(type, SCHEDULER_DISABLE.remark(jobName));
        } else if (type == SCHEDULER_SYNC) {
            createLog(type, SCHEDULER_SYNC.remark());
        }
    }

    public void createAdminLog(OperationType type, Object... querys) {
        Object query = (querys != null && querys.length > 0) ? querys[0] : null;
        String adminAccount = null;
        if (query != null) {
            if (query.getClass() == Integer.class) {
                adminAccount = adminDAO.get((Integer) query, Admin.ACCOUNT).getAccount();
            } else if (List.class.isAssignableFrom(query.getClass())) {
                adminAccount = CollectionUtil.join(adminDAO.findColumn(Query.inQuery(Admin.ID, query), Admin.NAME, true, true), ",");
            } else if (query.getClass() == Admin.class) {
                adminAccount = ((Admin) query).getAccount();
            }
        }
        if (type == ADMIN_CREATE) {
            createLog(type, ADMIN_CREATE.remark(adminAccount));
        } else if (type == ADMIN_DELETE) {
            createLog(type, ADMIN_DELETE.remark(adminAccount));
        } else if (type == ADMIN_DISABLE) {
            createLog(type, ADMIN_DISABLE.remark(adminAccount));
        } else if (type == ADMIN_ENABLE) {
            createLog(type, ADMIN_ENABLE.remark(adminAccount));
        } else if (type == ADMIN_ALLOCATE) {
            createLog(type, ADMIN_ENABLE.remark(adminAccount));
        }
    }

    public void createRoleLog(OperationType type, Object... querys) {
        Object query = (querys != null && querys.length > 0) ? querys[0] : null;
        String roleName = null;
        if (query != null) {
            if (query.getClass() == Integer.class) {
                roleName = roleDAO.get((Integer) query, Role.NAME).getName();
            } else if (query.getClass() == Role.class) {
                roleName = ((Role) query).getName();
            }
        }
        if (type == ROLE_CREATE) {
            createLog(type, ROLE_CREATE.remark(roleName));
        } else if (type == ROLE_UPDATE) {
            createLog(type, ROLE_UPDATE.remark(roleName));
        } else if (type == ROLE_DELETE) {
            createLog(type, ROLE_DELETE.remark(roleName));
        }
    }

    public void createZKBackupLog(OperationType type, Object... querys) {
        Object query = (querys != null && querys.length > 0) ? querys[0] : null;
        String backupPath = null;
        if (query != null) {
            if (query.getClass() == Integer.class) {
                backupPath = zkBackupDAO.get((Integer) query, ZkBackup.PATH).getPath();
            } else if (query.getClass() == ZkBackup.class) {
                backupPath = ((ZkBackup) query).getPath();
            }
        }
        if (type == ZK_BACKUP_CREATE) {
            createLog(type, ZK_BACKUP_CREATE.remark(backupPath));
        } else if (type == ZK_BACKUP_DELETE) {
            createLog(type, ZK_BACKUP_DELETE.remark(backupPath));
        }
    }

    public void createBuildStatLog(OperationType type) {
        if (type == BUILD_HOUR_STAT) {
            createLog(type, BUILD_HOUR_STAT.remark(DateUtil.getDateString(new Date(), "yyyy-MM-dd HH点")));
        } else if (type == BUILD_DAY_STAT) {
            createLog(type, BUILD_DAY_STAT.remark(DateUtil.getDateString(new Date(), "yyyy-MM-dd")));
        } else if (type == BUILD_MONTH_STAT) {
            createLog(type, BUILD_MONTH_STAT.remark(DateUtil.getDateString(new Date(), "yyyy-MM")));
        }
    }

    public void createExpiredDataLog() {
        createLog(EXPIRED_DATA_DELETE, EXPIRED_DATA_DELETE.remark());
    }

    public void createGatherLog(OperationType type) {
        if (type == GATHER_SOLR) {
            createLog(type, GATHER_SOLR.remark());
        } else if (type == GATHER_ZK) {
            createLog(type, GATHER_ZK.remark());
        }
    }

    public void createSolrConfigLog(OperationType type, Object... querys) {
        Object query = (querys != null && querys.length > 0) ? querys[0] : null;
        String configPath = "";
        if (query != null) {
            if (query.getClass() == Integer.class) {
                configPath = zkNodeDAO.get((Integer) query, ZkNode.PATH).getPath();
            } else if (List.class.isAssignableFrom(query.getClass())) {
                configPath = CollectionUtil.join(zkNodeDAO.findColumn(Query.inQuery(ZkNode.ID, query), ZkNode.PATH, true, true), "");
            }
        }
        if (type == SOLR_CONFIG_CREATE) {
            createLog(type, SOLR_CONFIG_CREATE.remark(configPath));
        } else if (type == SOLR_CONFIG_UPDATE) {
            createLog(type, SOLR_CONFIG_UPDATE.remark(configPath));
        } else if (type == SOLR_CONFIG_DELETE) {
            createLog(type, SOLR_CONFIG_DELETE.remark(configPath));
        }
    }

    public void createSolrCollectionLog(OperationType type, Object... querys) {
        Object query = (querys != null && querys.length > 0) ? querys[0] : null;
        String collectionName = "";
        if (query != null) {
            if (query.getClass() == Integer.class) {
                collectionName = solrCollectionDAO.get((Integer) query, SolrCollection.NAME).getName();
            }
        }
        if (type == SOLR_COLLECTION_CREATE) {
            createLog(type, SOLR_COLLECTION_CREATE.remark(collectionName));
        } else if (type == SOLR_COLLECTION_UPDATE) {
            createLog(type, SOLR_COLLECTION_UPDATE.remark(collectionName));
        } else if (type == SOLR_COLLECTION_DELETE) {
            createLog(type, SOLR_COLLECTION_DELETE.remark(collectionName));
        } else if (type == SOLR_COLLECTION_RELOAD) {
            createLog(type, SOLR_COLLECTION_RELOAD.remark(collectionName));
        } else if (type == SOLR_COLLECTION_OPTIMIZE) {
            createLog(type, SOLR_COLLECTION_OPTIMIZE.remark(collectionName, (query != null && querys.length > 2) ? querys[1] : 1));
        }
    }

    public void createSolrNodeLog(OperationType type, Object... querys) {
        Object query = (querys != null && querys.length > 0) ? querys[0] : null;
        String nodeName = "";
        if (query != null) {
            if (query.getClass() == Integer.class) {
                nodeName = solrNodeDAO.get((Integer) query, SolrNode.NAME).getName();
            }
        }
        if (type == SOLR_NODE_DELETE) {
            createLog(type, SOLR_NODE_DELETE.remark(nodeName));
        }
    }

    public void createSolrReplicaLog(OperationType type, Object... querys) {
        Object query = (querys != null && querys.length > 0) ? querys[0] : null;
        String replicaName = "";
        if (query != null) {
            if (query.getClass() == Integer.class) {
                SolrReplica replica = solrReplicaDAO.get((Integer) query);
                replicaName = solrReplicaDAO.getNameMap(CollectionUtil.asList(replica.getId()), true).get(replica.getId());
            }
        }
        if (type == SOLR_REPLICA_CREATE) {
            createLog(type, SOLR_REPLICA_CREATE.remark(replicaName));
        } else if (type == SOLR_REPLICA_DELETE) {
            createLog(type, SOLR_REPLICA_DELETE.remark(replicaName));
        }
    }

    public void createSolrDataLog(OperationType type, Integer collectionId) {
        String collectionName = solrCollectionDAO.get(collectionId, SolrCollection.NAME).getName();
        if (type == SOLR_DATA_UPDATE) {
            createLog(type, SOLR_DATA_UPDATE.remark(collectionName));
        } else if (type == SOLR_DATA_DELETE) {
            createLog(type, SOLR_DATA_DELETE.remark(collectionName));
        }
    }

    /**
     * 创建请求日志
     *
     * @query type
     */
    private void createLog(OperationType type, String remark) {
        String ip = RequestContext.getIp();
        Admin operator = RequestContext.getAdmin();
        if (operator != null && StringUtil.isNotEmpty(ip)) {
            create(type, remark, ip, operator.getId());
        } else {
            try {
                ip = InetAddress.getLocalHost().getHostAddress();
            } catch (Exception ignored) {
                ip = "127.0.0.1";
            }
            create(type, remark, ip, 0);
        }
    }

    private void create(OperationType type, String remark, String ip, Integer adminId) {
        OperationLog log = new OperationLog(type.value(), remark, ip, adminId);
        log.setOptTime(System.currentTimeMillis());
        operationLogDAO.create(log);
    }

    /**
     * 清除过期的操作日志
     *
     * @query expiredTime
     */
    public void clearExpiredOperateData(long expiredTime) {
        Query query = Query.neqQuery(OperationLog.ADMIN_ID, 0).lt(OperationLog.OPT_TIME, expiredTime);
        operationLogDAO.delete(query);
    }

    /**
     * 清除过期的调度日志
     *
     * @query expiredTime
     */
    public void clearExpiredSchedulerData(long expiredTime) {
        Query query = Query.query(OperationLog.ADMIN_ID, 0).lt(OperationLog.OPT_TIME, expiredTime);
        operationLogDAO.delete(query);
    }
}